﻿using System;
using System.Text;
using System.ComponentModel;

namespace Tilver.Coder.Core
{
    /// <summary>
    /// 数据加载基类
    /// </summary>
    public abstract class LoaderBase
    {
        #region 字段
        /// <summary>
        /// 将要处理的总数
        /// </summary>
        protected uint Count; 
        /// <summary>
        /// 当前处理到的位置
        /// </summary>
        protected uint Position;
        /// <summary>
        /// 后台处理线程
        /// </summary>
        protected BackgroundWorker Worker = new BackgroundWorker();
        /// <summary>
        /// 要加载的项目
        /// </summary>
        public CoderProject Project { get; set; }
        /// <summary>
        /// 返回信息
        /// </summary>
        public string Message { get { return _response.ToString(); } }
        #endregion

        #region 私有字段
        /// <summary>
        /// 输入字符串
        /// </summary>
        private StringBuilder _response = new StringBuilder();
        #endregion

        /// <summary>
        /// 进度变化事件
        /// </summary>
        public event LoadProgressChangedEventHandler LoadProgressChanged;
        /// <summary>
        /// 加载完成事件
        /// </summary>
        public event LoadCompleteEventHandler LoadComplete;
        /// <summary>
        /// 加载数据库完成事件
        /// </summary>
        public event EventHandler<LoadDataBaseCompletedEventArgs> LoadDataBaseCompleted;

        protected LoaderBase()
        {
            Worker.WorkerReportsProgress = true;
            Worker.WorkerSupportsCancellation = true;
            Worker.DoWork += new DoWorkEventHandler(_worker_DoWork);
            Worker.ProgressChanged += new ProgressChangedEventHandler(_worker_ProgressChanged);
            Worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_worker_RunWorkerCompleted);
        }
        /// <summary>
        /// 线程执行完成
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            OnLoadCompleted(new LoadCompleteEventArgs(this.Project, e.Error, e.Cancelled, e.UserState));
        }
        /// <summary>
        /// 进度处理事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void _worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            OnLoadProgressChanged(new LoadProgressChangedEventArgs(e.ProgressPercentage, e.UserState.ToString(), e.UserState));
        }
        /// <summary>
        /// 加载数据库
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void _worker_DoWork(object sender, DoWorkEventArgs e)
        {
            if (Project == null)
            {
                throw new ApplicationException("");
            }
            foreach (var cDataBase in Project.DataBases)
            {
                LoadDataBase(cDataBase);
            }
        }
        /// <summary>
        /// 进度加载
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnLoadProgressChanged(LoadProgressChangedEventArgs e)
        {
            if (LoadProgressChanged != null)
            {
                LoadProgressChanged(this, e);
            }
        }
        /// <summary>
        /// 数据加载完成
        /// </summary>
        protected virtual void OnLoadCompleted(LoadCompleteEventArgs e)
        {
            if (LoadComplete != null)
            {
                LoadComplete(this, e);
            }
        }
        /// <summary>
        /// 加载数据库完成
        /// </summary>
        /// <param name="dataBase"></param>
        protected virtual void OnLoadDataBaseCompleted(CoderDataBase dataBase)
        {
            if (LoadDataBaseCompleted != null)
            {
                LoadDataBaseCompleted(this, new LoadDataBaseCompletedEventArgs(dataBase));
            }
        }
        /// <summary>
        /// 进度消息通知
        /// </summary>
        /// <param name="userState"></param>
        protected void ReportProgress(object userState)
        {
            Worker.ReportProgress(0, userState);
        }
        /// <summary>
        /// 执行后台处理程序
        /// </summary>
        public void LoadSync()
        {
            Worker.RunWorkerAsync();
        }
        /// <summary>
        /// 加载项目中的多个数据库
        /// </summary>
        /// <param name="cDataBase"></param>
        public abstract void LoadDataBase(CoderDataBase cDataBase);

    }

    /// <summary>
    /// 加载数据库事件消息
    /// </summary>
    public class LoadDataBaseCompletedEventArgs : EventArgs
    {
        public CoderDataBase DataBase { get; private set; }

        public LoadDataBaseCompletedEventArgs(CoderDataBase dataBase)
        {
            DataBase = dataBase;
        }
    }

    /// <summary>
    /// 加载数据进度条事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    public delegate void LoadProgressChangedEventHandler(object sender, LoadProgressChangedEventArgs e);
    /// <summary>
    /// 加载进度变化事件
    /// </summary>
    public class LoadProgressChangedEventArgs : ProgressChangedEventArgs
    {
        public string Message { get; private set; }

        public LoadProgressChangedEventArgs(int progressPercentage, string message, object userState)
            : base(progressPercentage, userState)
        {
            Message = message;
        }
    }

    /// <summary>
    /// 加载完成事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="args"></param>
    public delegate void LoadCompleteEventHandler(object sender, LoadCompleteEventArgs args);
    /// <summary>
    /// 加载完成
    /// </summary>
    public class LoadCompleteEventArgs : AsyncCompletedEventArgs
    {
        private readonly CoderProject _protect;

        public CoderProject Project
        {
            get
            {
                RaiseExceptionIfNecessary();
                return _protect;
            }
        }

        public LoadCompleteEventArgs(CoderProject project, Exception error, bool cancelled, object userState)
            : base(error, cancelled, userState)
        {
            _protect = project;
        }
    }
}
